package com.mrzhou.web.util;

import com.mrzhou.core.tool.api.CloudUser;
import com.mrzhou.core.tool.api.R;
import com.mrzhou.core.tool.constants.CloudConstant;
import com.mrzhou.core.tool.constants.StringSymbol;
import com.mrzhou.core.tool.constants.TokenConstant;
import com.mrzhou.core.tool.utils.Func;
import com.mrzhou.core.tool.utils.JacksonUtil;
import com.mrzhou.core.tool.utils.JwtUtil;
import com.mrzhou.core.tool.utils.StringUtil;
import io.jsonwebtoken.Claims;
import org.apache.commons.io.Charsets;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;

/**
 * 操作request和response中的数据工具类
 *  解析请求头中的token, 并返回对象
 */
public class WebUtil extends WebUtils {

    public static final String USER_AGENT_HEADER = "user-agent";

    /**
     * 获取request中的token
     */
    public static String getAuthToken() {
        HttpServletRequest request = getRequest();
        if(null == request) {
            return null;
        }
        String headerToken = request.getHeader(TokenConstant.TOKEN_HEADER_NAME);
        String paramToken = request.getParameter(TokenConstant.TOKEN_PARAM_NAME);
        return StringUtil.isNotBlank(headerToken) ? headerToken : paramToken;
    }

    public static CloudUser getUser() {
        HttpServletRequest request = getRequest();
        if(request == null) {
            return null;
        }
        Claims claims = JwtUtil.parseJwt(JwtUtil.getToken(getAuthToken()));
        if(claims == null) {
            return null;
        }
        CloudUser cloudUser = new CloudUser();
        cloudUser.setAccount(Func.toStr(claims.get(TokenConstant.ACCOUNT)));
        cloudUser.setClientId(Func.toStr(claims.get(TokenConstant.CLIENT_ID)));
        cloudUser.setDeptId(Func.toLong(claims.get(TokenConstant.DEPT_ID)));
        cloudUser.setPhone(Func.toStr(claims.get(TokenConstant.PHONE)));
//        cloudUser.setRoleId(Func.toStr(claims.get(TokenConstant.ROLE_ID)));
        cloudUser.setRoleName(Func.toStr(claims.get(TokenConstant.ROLE_NAME)));
        cloudUser.setUserId(Func.toLong(claims.get(TokenConstant.USER_ID)));
        return cloudUser;
    }

    public static String getAccount() {
        CloudUser cloudUser = getUser();
        return null != cloudUser ? cloudUser.getAccount() : null;
    }

    public static Long getUserId() {
        CloudUser cloudUser = getUser();
        return null != cloudUser ? cloudUser.getUserId() : null;
    }

    /**
     * 通过Spring框架自带的方式获取上下文中的Request
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return attributes == null ? null : ((ServletRequestAttributes)attributes).getRequest();
    }

    public static String getParameter(String name) {
        return getRequest().getParameter(name);
    }

    public static String getIp() {
        return getIp(getRequest());
    }

    public static String getUri() {
        return getRequest().getRequestURI();
    }

    /**
     * 获取ip地址
     */
    public static String getIp(@Nullable HttpServletRequest request){
        String ip = null;

        //X-Forwarded-For：Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP：apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP：weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP：有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP：nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
    }

    public static void writerError(R<?> result, HttpServletResponse response, int code) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(code);
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(JacksonUtil.toJsonString(result));
    }

    /***
     * 获取 request 中 json 字符串的内容
     *
     * @param request request
     * @return 字符串内容
     */
    public static String getRequestParamString(HttpServletRequest request) {
        try {
            return getRequestStr(request);
        } catch (Exception ex) {
            return StringSymbol.EMPTY;
        }
    }

    public static String getRequestStr(HttpServletRequest request) throws IOException {
        String queryString = request.getQueryString();
        if (StringUtil.isNotBlank(queryString)) {
            return new String(queryString.getBytes(Charsets.ISO_8859_1), Charsets.UTF_8).replaceAll("&amp;", "&").replaceAll("%22", "\"");
        }
        return getRequestStr(request, getRequestBytes(request));
    }

    /**
     * 获取 request 请求的 byte[] 数组
     */
    public static byte[] getRequestBytes(HttpServletRequest request) throws IOException {
        int contentLength = request.getContentLength();
        if (contentLength < 0) {
            return null;
        }
        byte[] buffer = new byte[contentLength];
        for (int i = 0; i < contentLength; ) {
            int readlen = request.getInputStream().read(buffer, i, contentLength - i);
            if (readlen == -1) {
                break;
            }
            i += readlen;
        }
        return buffer;
    }

    /**
     * 获取 request 请求内容
     *
     * @param request request
     * @param buffer  buffer
     * @return String
     * @throws IOException IOException
     */
    public static String getRequestStr(HttpServletRequest request, byte[] buffer) throws IOException {
        String charEncoding = request.getCharacterEncoding();
        if (charEncoding == null) {
            charEncoding = StringSymbol.UTF_8;
        }
        String str = new String(buffer, charEncoding).trim();
        if (StringUtil.isBlank(str)) {
            StringBuilder sb = new StringBuilder();
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String key = parameterNames.nextElement();
                String value = request.getParameter(key);
                StringUtil.appendBuilder(sb, key, "=", value, "&");
            }
            str = StringUtil.removeSuffix(sb.toString(), "&");
        }
        return str.replaceAll("&amp;", "&");
    }

    public static String getPath(String uriStr) {
        URI uri;
        try {
            uri = new URI(uriStr);
        } catch (URISyntaxException exception) {
            throw new RuntimeException(exception);
        }
        return uri.getPath();
    }

    /**
     * 获取调用链id
     * @return
     */
    public static String getCloudId() {
        HttpServletRequest request = getRequest();
        return request.getHeader(CloudConstant.HEADER_CLOUD_ID);
    }

}
